<?php
/**
 * @file
 * @author  Jakub Kraft <jakub.kraft@gmail.com>
 * @version 1.0
 */

class OembedAdapter {
	
	# array with the oEmbed response before conversion to JSON or anything else
	protected $response = array();
	
	# cached curl result if any is available
	protected $curl_result = null;
	
	# pattern that says which URLs this class can resolve - in this case any URL
	public static $pattern = '/[.]*/i';
	
	# HTTP response codes that are accepted as success - NOT USED YET
	protected $acceptedHTTPCodes = array(200, 201, 202, 203, 204, 205, 206);
	
	# constructor method
	public function __construct ($curl_result = null) {
		$this->curl_result = $curl_result;
	}
	
	# just a placeholder, descendants have to implement this
	public function resolveURL($url) {
		return array();
	}
	
	# a method to retrieve a URL via curl
	public function _curlCall($url, $headers) {
		
		# prepare curl settings
		$curl_settings = array(
			CURLOPT_URL => $url,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_HEADER => $headers,
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; oEmbed.php 1.0)',
			CURLOPT_MAXREDIRS => 10,
			CURLOPT_CONNECTTIMEOUT => 10
		);
		
		# make curl request
		$curl = curl_init();
		curl_setopt_array($curl, $curl_settings);
		$str = curl_exec($curl);
		$info = curl_getinfo($curl);
		curl_close($curl);
		
		#return what we've got and store it
		$this->curl_result = array(
			'response' => $str,
			'info' => $info
		);
		return $this->curl_result;
	}
	
	# method providing access to the private property curl_result
	public function getCurlResult () {
		return $this->curl_result;
	}
	
}

class GenericOEmbedAdapter extends OEmbedAdapter {
	
	public function resolveURL($url) {
		
		# init the response
		$this->response = array();
		$this->response['version'] = '1.0';
		$this->response['type'] = 'link';
		$this->response['requested_url'] = trim($url);

		$this->_curlCall($this->response['requested_url'], true);
		
		# TODO: vyresit HTTP kody 3xx novym pozadavkem
		
		# if we got something, we process it 
		if (is_string($this->curl_result['response']) && strlen($this->curl_result['response']) > 0) {
			# resolve title
			# TODO: nektere title to nebere, prestoze ve strance jsou
			if (preg_match('/\<title\>(?P<title>[^\<]+)\<\/title\>/i', $this->curl_result['response'], $found)) {
				$this->response['title'] = trim($found['title']);
			} else {
				$this->response['title'] = '';
			}
			
			# thumbnail for fb if available
			if (preg_match('/(?P<link>\<link[^>]+image\_src[^>]*\>)/i', $this->curl_result['response'], $found)) {
				preg_match('/href[\s]*\=[\s]*\"(?P<image_url>[^\"]*)\"/i', $found['link'], $found2);
				$this->response['thumbnail_url'] = trim($found2['image_url']);
			}
			
			# description - not part of oEmbed specification
			if (preg_match('/(?P<description>\<meta[^>]+name[\s]*\=[\s]*\"description\"[^>]*\>)/i', $this->curl_result['response'], $found)) {
				preg_match('/content[\s]*\=[\s]*\"(?P<description>[^\"]*)\"/i', $found['description'], $found2);
				$this->response['description'] = trim($found2['description']);
			}
			
			# provider
			$purl = parse_url($this->response['requested_url']);
			$this->response['provider_name'] = $purl['host'];
			$this->response['provider_url'] = $purl['scheme'].'://'.$purl['host'].'/';
			
			# favicon
			if (preg_match('/(?P<favicon>\<link[^>]+rel[\s]*\=[\s]*\"(icon|shortcut icon)\"[^>]*\>)/i', $this->curl_result['response'], $found)) {
				preg_match('/href[\s]*\=[\s]*\"(?P<favicon>[^\"]*)\"/i', $found['favicon'], $found2);
				$this->response['favicon_url'] = trim($found2['favicon']);
				$purl = parse_url($this->response['favicon_url']);
				if (!$purl['scheme']) {
					$this->response['favicon_url'] = $this->response['provider_url'].$this->response['favicon_url'];
				}
			} else {
				# TODO: try searching for the favicon via curl
				$this->response['favicon_url'] = $this->response['provider_url'].'favicon.ico';
			}
			
		}
		
		# return the array with response
		return $this->response;
	}
	
}

class OEmbed {
	
	private $defaultAdapter = '';
	private $adapters = array();
	private $response = array();
	
	public function __construct () {
		$this->defaultAdapter = 'GenericOEmbedAdapter'; 
	}
	
	public function registerAdapters ($adapters) {
		$this->adapters = array_merge($this->adapters, (array)$adapters);
	}
	
	public function resolveURL ($url) {
		if ($this->response['url'] != $url) { # prevent resolving the same url again
			
			# make the default request and store the content for use in the other adapters
			$def = new $this->defaultAdapter();
			$this->response = $def->resolveURL($url);
			$curl_result = $def->getCurlResult();
			
			foreach ($this->adapters as $adapter) {
				eval('$pattern = '.$adapter.'::$pattern;'); # workaround for PHP < 5.3.0 - if you run this or higher version "$pattern = $adapter::$pattern;" should work as well
				if (preg_match($pattern,$url)) {
					$adp = new $adapter($curl_result);
					$this->response = array_merge($this->response, $adp->resolveURL($url));
				}
			}
		}
	}
	
	public function getJSON () {
		return json_encode($this->response);
	}
	
	public function getArray () {
		return $this->response;
	}
	
}